package com.anche.cywebnew.Utils.HikUtil;

import com.anche.cywebnew.DAO.configManager.SysOptionMapper;
import com.anche.cywebnew.DTO.HikBaseDTO;
import com.anche.cywebnew.Utils.Spring.SpringBeanFactoryUtils;
import com.sun.jna.Native;
import com.sun.jna.NativeLong;
import com.sun.jna.Pointer;
import com.sun.jna.ptr.IntByReference;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;

import java.text.MessageFormat;

public class CommonUtil {

    private static final Logger logger = LoggerFactory.getLogger(CommonUtil.class);

    @Autowired
    private SysOptionMapper sysOptionMapper;

    HCNetSDK hCNetSDK;

    NativeLong lUserID;

    HCNetSDK.NET_DVR_PICCFG_V30 m_struPicCfg;

    String errMsg = "%s，错误原因：%s，错误描述：%s。";

    String resultMsg = "";

    public CommonUtil() {
        if (sysOptionMapper == null) {
            sysOptionMapper = (SysOptionMapper) SpringBeanFactoryUtils.getBean(SysOptionMapper.class);
        }
        String hikDllPath = sysOptionMapper.getOptionValue("录像下载配置", "hikDllPath", "1");
        hCNetSDK = (HCNetSDK) Native.loadLibrary(hikDllPath + "\\HCNetSDK.dll", HCNetSDK.class);
        lUserID = new NativeLong(-1);
    }

    /**
     * 海康控件初始化
     */
    public boolean doInit() {
        boolean initSuc = hCNetSDK.NET_DVR_Init();  //设备初始化操作
        if (initSuc) {
            logger.info("海康视频SDK初始化成功");
        } else {
            int code = hCNetSDK.NET_DVR_GetLastError();
            String msg = HikErrorUtil.getMsgByCode(code);
            resultMsg = String.format(errMsg, "海康视频SDK初始化失败", code, msg);
            logger.info("海康视频SDK初始化失败，code：[{}]，msg：[{}]", code, msg);
        }
        return initSuc;
    }

    /**
     * 设置连接时间
     *
     * @param waitTime 超时时间，单位毫秒，取值范围[300,75000]，实际最大超时时间因系统的connect超时时间而不同；
     * @param tryTimes 连接尝试次数（保留）
     */
    public void setConnectTime(int waitTime, int tryTimes) {
        if (!hCNetSDK.NET_DVR_SetConnectTime(waitTime, tryTimes)) {
            int code = hCNetSDK.NET_DVR_GetLastError();
            String msg = HikErrorUtil.getMsgByCode(code);
            resultMsg = String.format(errMsg, "设置链接时间失败", code, msg);
            logger.info("设置链接时间失败，code：[{}]，msg：[{}]。", code, msg);
        } else {
            logger.info("设置链接时间成功，超时时间：[{}]，连接尝试次数：[{}]。", waitTime, tryTimes);
        }
    }

    /**
     * 设置重新连接时间
     *
     * @param interval    重连间隔，单位:毫秒
     * @param enableRecon 是否重连，false-不重连，true-重连
     */
    public void setReconnect(int interval, boolean enableRecon) {
        if (!hCNetSDK.NET_DVR_SetReconnect(interval, enableRecon)) {
            int code = hCNetSDK.NET_DVR_GetLastError();
            String msg = HikErrorUtil.getMsgByCode(code);
            resultMsg = String.format(errMsg, "设置重连接失败", code, msg);
            logger.info("设置重连接失败，code：[{}]，msg：[{}]。", code, msg);
        } else {
            logger.info("设置重连接失败，重连间隔：[{}]，是否重连：[{}]。", interval, enableRecon);
        }
    }

    /**
     * 登陆硬盘录像机
     *
     * @param hikBaseDTO      硬盘录像机基本信息
     * @param m_strDeviceInfo 设备信息
     * @return 用户登录句柄
     */
    public NativeLong doLogin(HikBaseDTO hikBaseDTO, HCNetSDK.NET_DVR_DEVICEINFO_V30 m_strDeviceInfo) {
        String ip = hikBaseDTO.getIp();
        short port = hikBaseDTO.getPort();
        String yh = hikBaseDTO.getYh();
        String mm = hikBaseDTO.getMm();
        lUserID = hCNetSDK.NET_DVR_Login_V30(ip, port,
                yh, mm, m_strDeviceInfo);
        if (lUserID.longValue() != -1) {
            logger.info("登录设备IP：[{}]，端口：[{}]，用户名：[{}]，密码：[{}]成功", ip, port, yh, mm);
        } else {
            int code = hCNetSDK.NET_DVR_GetLastError();
            String msg = HikErrorUtil.getMsgByCode(code);
            resultMsg = String.format(errMsg, "登录设备失败", code, msg);
            logger.info("登录设备IP：[{}]，端口：[{}]，用户名：[{}]，密码：[{}]失败，code：[{}]，msg：[{}]", ip, port, yh, mm, code, msg);
        }
        return lUserID;
    }

    /**
     * 登陆硬盘录像机
     *
     * @param hikBaseDTO 硬盘录像机基本信息
     * @return 用户登录句柄
     */
    public NativeLong doLogin(HikBaseDTO hikBaseDTO) {
        HCNetSDK.NET_DVR_DEVICEINFO_V30 m_strDeviceInfo = new HCNetSDK.NET_DVR_DEVICEINFO_V30();
        String ip = hikBaseDTO.getIp();
        short port = hikBaseDTO.getPort();
        String yh = hikBaseDTO.getYh();
        String mm = hikBaseDTO.getMm();
        logger.info("设备IP：[{}]，端口：[{}]，用户名：[{}]，密码：[{}]", ip, port, yh, mm);
        NativeLong lUserID = hCNetSDK.NET_DVR_Login_V30(ip, port, yh, mm, m_strDeviceInfo);
        if (lUserID.longValue() != -1) {
            logger.info("登录设备IP：[{}]，端口：[{}]，用户名：[{}]，密码：[{}]成功", ip, port, yh, mm);
        } else {
            int code = hCNetSDK.NET_DVR_GetLastError();
            String msg = HikErrorUtil.getMsgByCode(code);
            resultMsg = String.format(errMsg, "登录设备失败", code, msg);
            logger.info("登录设备IP：[{}]，端口：[{}]，用户名：[{}]，密码：[{}]失败，code：[{}]，msg：[{}]", ip, port, yh, mm, code, msg);
        }
        return lUserID;
    }

    /**
     * 登出用户
     *
     * @return
     */
    public boolean doLogout() {
        boolean logout = hCNetSDK.NET_DVR_Logout(lUserID);
        if (logout) {
            logger.info("用户登出成功");
        } else {
            int code = hCNetSDK.NET_DVR_GetLastError();
            String msg = HikErrorUtil.getMsgByCode(code);
            resultMsg = String.format(errMsg, "用户登出成功失败", code, msg);
            logger.info("用户登出成功失败，code：[{}]，msg：[{}]", code, msg);
        }
        return logout;
    }

    /**
     * 登出用户
     *
     * @param userid 用户句柄
     * @return
     */
    public boolean doLogout(NativeLong userid) {
        boolean logout = hCNetSDK.NET_DVR_Logout(userid);
        if (logout) {
            logger.info("用户登出成功");
        } else {
            int code = hCNetSDK.NET_DVR_GetLastError();
            String msg = HikErrorUtil.getMsgByCode(code);
            resultMsg = String.format(errMsg, "用户登出成功失败", code, msg);
            logger.info("用户登出成功失败，code：[{}]，msg：[{}]", code, msg);
        }
        return logout;
    }

    /**
     * 获取设备配置信息
     *
     * @param command
     * @param ch
     * @return
     */
    public Object getDVRConfig(int command, NativeLong ch) {
        switch (command) {
            case 1002:
                IntByReference ibrBytesReturned = new IntByReference(0);//获取图片参数
                m_struPicCfg = new HCNetSDK.NET_DVR_PICCFG_V30();
                m_struPicCfg.write();
                Pointer lpPicConfig = m_struPicCfg.getPointer();
                boolean getDVRConfigSuc = hCNetSDK.NET_DVR_GetDVRConfig(lUserID, command,
                        ch, lpPicConfig, m_struPicCfg.size(), ibrBytesReturned);
                m_struPicCfg.read();
                if (getDVRConfigSuc) {
                    logger.info("获取图片参数成功");
                } else {
                    logger.info("获取图片参数失败");
                    int code = hCNetSDK.NET_DVR_GetLastError();
                    String msg = HikErrorUtil.getMsgByCode(code);
                    logger.info("获取图片参数失败：code：[{}]，msg：[{}]", code, msg);
                }
                return m_struPicCfg;
            default:
                logger.info("暂时不支持获取图片参数外其他参数");
        }
        return null;
    }

    /**
     * 释放SDK资源
     *
     * @return
     */
    public boolean doDestroy() {
        boolean logout = hCNetSDK.NET_DVR_Cleanup();
        if (logout) {
            logger.info("SDK资源释放成功");
        } else {
            int code = hCNetSDK.NET_DVR_GetLastError();
            String msg = HikErrorUtil.getMsgByCode(code);
            resultMsg = String.format(errMsg, "SDK资源释放失败", code, msg);
            logger.info("SDK资源释放失败，code：[{}]，msg：[{}]", code, msg);
        }
        return logout;
    }

    /**
     * 获取错误信息
     *
     * @return
     */
    public String getLastError() {
        return resultMsg;
    }
}
